package io.gitee.twoke.generator.engine.impl.generate.output;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class DefaultOutputInterceptorChain implements OutputInterceptorChain,
        OutputExecutor {

    private int currentIndex = 0;
    private List<OutputInterceptor> interceptors;
    private OutputExecutor finallyLastExecutor;

    public DefaultOutputInterceptorChain(OutputExecutor finallyLastExecutor) {
        this.interceptors = new ArrayList<>();
        this.currentIndex = 0;
        this.finallyLastExecutor = finallyLastExecutor;
    }

    public DefaultOutputInterceptorChain() {
        this(null);
    }

    @Override
    public OutputInterceptorChain addInterceptor(OutputInterceptor interceptor) {
        if (!this.interceptors.contains(interceptor)) {
            this.interceptors.add(interceptor);
        }
        return this;
    }

    @Override
    public OutputInterceptorChain removeInterceptor(OutputInterceptor interceptor) {
        if (this.interceptors.contains(interceptor)) {
            this.interceptors.remove(interceptor);
        }
        return this;
    }

    @Override
    public List<OutputInterceptor> getInterceptors() {
        return interceptors;
    }
    @Override
    public OutputExecutor getFinallyLastExecutor() {
        return finallyLastExecutor;
    }
    @Override
    public OutputInterceptorChain setFinallyLastExecutor(OutputExecutor finallyLastExecutor) {
        this.finallyLastExecutor = finallyLastExecutor;
        return this;
    }

    @Override
    public void execute(OutputEntity output) {
        if (interceptors.size() > 0) {
            currentIndex = 0;
            doExecute(interceptors.get(currentIndex), output);
        }
        if (finallyLastExecutor != null) {
            doExecute((chain, entity) -> {
                finallyLastExecutor.execute(entity);
            }, output);
        }
    }

    @Override
    public void doNext(OutputEntity outputEntity) {
        currentIndex++;
        if (currentIndex < interceptors.size()) {
            doExecute(interceptors.get(currentIndex), outputEntity);
        }
    }

    public void doExecute(OutputInterceptor interceptor, OutputEntity outputEntity) {
        String classSimpleName = getClassSimpleName(interceptor);
        log.debug(">>>>>>>>>> enter {}", classSimpleName);
        interceptor.execute(this, outputEntity);
        log.debug("filename {}", outputEntity.getFilename());
        log.debug("output path {}", outputEntity.getOutputPath());
        log.debug("params {}", outputEntity.getParams());
        log.debug(">>>>>>>>>> leave {}", classSimpleName);
    }

    private String getClassSimpleName(OutputInterceptor interceptor) {
        String simpleName = interceptor.getClass().getSimpleName();
        return  simpleName.startsWith(DefaultOutputInterceptorChain.class.getSimpleName()) ? "FinallyLastOutputInterceptor" : simpleName;
    }

}